<?php
/**
 * NP_WPSandBox sub class
 *
 * WPSandBox skin variables parser Class
 *
 * This file is the plugin which makes sure that "SandBox" of "WordPress" can be used by "NucleusCMS".
 * Please see a {@link http://www.plaintxt.org/themes/sandbox/ link destination} about details of "SandBox".
 *
 * @author shizuki <shizuki@kinezumi.net>
 * @license http://nucleuscms.org/license.txt GNU General Public License
 * @copyright Copyright (C) 2002-2009 The Nucleus Group
 * @version $Id: SandBoxParser.inc.php 67 2009-03-09 04:35:03Z shizuki17xx $
 */

class SandBoxParser extends WPSandBox
{

// {{{ propaties

/**
 * Class properties
 */

/**
 * @name $zebra
 * @var array
 */
static protected  $zebra;

/**
 * @name $numbering
 * @var array
 */
static protected  $numbering;

// }}}
// {{{ constructor

/**
 * Construct
 */

	// {{{ __construct()

	/**
	 * Construct
	 *
	 * Plugin initialize
	 */
	public function __construct()
	{
		self::$zebra     = array();
		self::$numbering = array();
	}

	// }}}

// }}}
// {{{ Parser methods

/**
 * Parsers Sandbox skin variables
 */

	// {{{ parse_meta($b, $bid, $template)

	/**
	 * Parse <%meta%> tag
	 *
	 * Make 'WPSandBoxWPMETAEmulate' event occur.
	 *
	 * @param object current BLOG object
	 * @param int current blog ID
	 * @param string template fo metadata
	 * @return string metadata
	 **/
	public function parse_meta($b, $bid, $template)
	{
		global $manager;
		$meta = array();
		$ret  = '';
		$manager->notify('WPSandBoxWPMETAEmulate',
			array(
				'blog'   => $b,
				'blogid' => $bid,
				'meta'   => &$meta,
			)
		);
		foreach ($meta as $plugname => $data) {
			if ($plug = parent::pluginCheck($plugname)) {
				$name = array('plugname' => $plug->getName());
			} else {
				continue;
			}
			$ret .= TEMPLATE::fill($template['SandBox_MetaData_extra_Head'], $name);
			foreach ($data as $key => $val) {
				$met  = array('contents' => $val);
				$ret .= TEMPLATE::fill($template['SandBox_MetaData_extra_Body'], $met);
			}
			$ret .= TEMPLATE::fill($template['SandBox_MetaData_extra_Foot'], array());
		}
		return $ret;
	}

	// }}}
	// {{{ parse_extrapagehead()

	/**
	 * Parse skinvar 'extrapagehead'
	 *
	 * Skin variable parser.
	 * <%WPSandBax(extrapagehead)%>
	 * Make 'WPSandBoxPrePageHead' event occur.
	 * And output extra page head
	 */
	public function parse_extrapagehead()
	{
		global $manager;
		$extraPagehead = '';
		$manager->notify('WPSandBoxPrePageHead',
			array(
				'extraPagehead' => &$extraPagehead,
				'skinType'      => parent::$skinType,
			)
		);
		echo $extraPagehead;
	}

	// }}}
	// {{{ parse_extrapagefoot()

	/**
	 * Parse skinvar 'extrapagefoot'
	 *
	 * Skin variable parser.
	 * <%WPSandBax(extrapagefoot)%>
	 * Make 'WPSandBoxPrePageFoot' event occur.
	 * And output extra page foot
	 */
	public function parse_extrapagefoot()
	{
		global $manager;
		$extraPagefoot = '';
		$manager->notify('WPSandBoxPrePageFoot',
			array(
				'extraPagefoot' => &$extraPagefoot,
				'skinType'      => parent::$skinType,
			)
		);
		echo $extraPagefoot;
	}

	// }}}
	// {{{ parse_dynamicsidebar($extra)

	/**
	 * Parse skinvar 'dynamicsidebar'
	 *
	 * Skin variable parser.
	 * <%WPSandBax(dynamicsidebar, n|templateName)%>
	 * 'n' is '1' or larger int.
	 * Make 'WPSandBoxDynamicSidebar' event occur.
	 *
	 * @param int skinvar 2nd argument
	 * @param string skinvar 3rd argument
	 */
	public function parse_dynamicsidebar($extra)
	{
		global $manager;
		list($position, $template) = explode('|', $extra);
		$manager->notify('WPSandBoxDynamicSidebar',
			array(
				'skinType' => parent::$skinType,
				'mode'     => intval($position),
				'template' => $template,
			)
		);
	}

	// }}}
	// {{{ parse_sandboxpostclass($extra, $item)

	/**
	 * Parse skinvar 'sandboxpostclass'
	 *
	 * Template variable parser.
	 * <%WPSandBax(sandboxpostclass)%>
	 * Output micro format class to each post's <DIV> tags.
	 *
	 * @param string skinvar 2nd argument
	 * @param object current item object
	 */
	protected function parse_sandboxpostclass($extra, $item)
	{
		global $CONF, $blog, $member, $catid;
		if (!isset($this->id[$id])) $this->id[$id] = 0;
		if (!isset(self::$zebra[$extra])) {
			self::$zebra[$extra] = true;
		}
		if (!isset(self::$numbering[$extra])) {
			self::$numbering[$extra] = 1;
		}
		if (is_object($item)) {
			$item = (array)$item;
		}
		if ($blog) {
			$b = &$blog;
		} else {
			global $manager;
			$b = &$manager->getBlog($CONF['DefaultBlog']);
		}
		$scat = false;
		$tags = self::tagCheck();
		if ($plugmulti = parent::pluginCheck('MultipleCategories')) {
			global $subcatid;
			$scat = $subcatid;
		}
		$data = self::itemClass($item, $b, 'post', $plugmulti, $tags);
		if (self::$zebra[$extra]) {
			$data .= ' alt';
			self::$zebra[$extra] = false;
		} else {
			self::$zebra[$extra] = true;
		}
		$data .= ' p' . self::$numbering[$extra]++;
		echo $data;
	}

	// }}}
	// {{{ parse_sandboxcommentclass($extra, $item, $comment)

	/**
	 * Parse skinvar 'sandboxcommentclass'
	 *
	 * Template variable parser.
	 * <%WPSandBax(sandboxcommentclass)%>
	 * Output micro format class to each post's <DIV> tags.
	 *
	 * @param string skinvar 2nd argument
	 * @param object current item object
	 * @param object current comment object
	 */
	protected function parse_sandboxcommentclass($extra, $item, $comment)
	{
		$commented = getdate($comment['timestamp']);
		$format    = 'comment single c-y%04d c-m%02d c-d%02d c-h%02d';
		$data      = sprintf($format, $year, $mon, $mday, $hours, $itemid, $author);
		if ($item['authorid'] == $comment['memberid']) {
			$data .= ' bypostauthor';
		}
		if ($comment['memberid']) {
			$author = MEMBER::createFromID($comment['memberid']);
			$data  .= ' byuser commentauthor-' . $author->getDisplayName();
		}
		if (self::$zebra[$extra]) {
			$data .= ' alt';
			self::$zebra[$extra] = false;
		} else {
			self::$zebra[$extra] = true;
		}
		$data .= ' c' . self::$numbering[$extra]++;
		echo $data;
	}

	// }}}
	// {{{ parse_sandboxbodyclass()

	/**
	 * Parse skinvar 'sandboxbodyclass'
	 *
	 * Skin variable parser.
	 * <%WPSandBax(sandboxbodyclass)%>
	 * Output micro format class to <BODY> tag.
	 */
	protected function parse_sandboxbodyclass()
	{
		global $CONF, $blog, $member, $catid;
		if ($blog) {
			$b = &$blog;
		} else {
			global $manager;
			$b = &$manager->getBlog($CONF['DefaultBlog']);
		}
		$timestmp = time() + ($b->getTimeOffset() * 3600);
		$today    = getdate($timestmp);
		$format   = 'nucleus y%04d m%02d d%02d h%02d';
		$cssClass = sprintf($format, $today['year'], $today['mon'], $today['mday'], $today['hours']);
		$scat     = false;
		$tags     = self::tagCheck();
		if ($plugmulti = parent::pluginCheck('MultipleCategories')) {
			global $subcatid;
			$scat = $subcatid;
		}
		switch (parent::$skinType) {
			case 'index':
				global $catid;
				$cssClass .= self::indexPageBodyClass($catid, $tags, $scat);
				break;
			case 'archive':
			case 'archivelist':
				$cssClass .= self::archivePageBodyClass();
				break;
			case 'search':
				$cssClass .= ' search';
				break;
			case 'error':
				$cssClass .= ' four04';
				break;
			case 'member':
				global $member;
				$cssClass .= self::memberPageBodyClass($member);
			case 'item':
				global $itemid, $manager;
				$item     =& $manager->getItem(intval($itemid), 0, 0);
				$cssClass .= self::itemClass($item, $b, 'body', $plugmulti, $tags);
				break;
			default:
				$ignors = array('header', 'footer', 'sidebar',);
				if (in_array(parent::$skinType, $ignores) || preg_match('|(contents)|', parent::$skinType)) {
					break;
				}
				$cssClass .= ' page page-template page-template-' . parent::$skinType;
				if (parent::$page > 0) {
					$cssClass .= ' page-paged-' . parent::$page;
				}
		}
		if ($catid) {
			$cssClass .= ' category category-' . $b->getCategoryName($catid);
			if (parent::$page > 0) {
				$cssClass .= ' category-paged-' . parent::$page;
			}
		}
		if (parent::$page > 0) {
			$cssClass .= ' paged page-' . parent::$page;
		}
		if (!empty($tags)) {
			$cssClass .= ' tag tag-' . implode(' s-tag-', $tags);
			if (parent::$page > 0) {
				$cssClass .= ' tag-paged-' . parent::$page;
			}
		}
		if ($member->isLoggedIn()) {
			$cssClass .= ' loggedin';
		}
		echo $cssClass;
	}

	// }}}
	// {{{ parse_globalnavi($template = 'Sandbox/sidebar')

	/**
	 * Parse skinvar 'globalnavi'
	 *
	 * Skin variable parser.
	 * <%WPSandBax(globalnavi)%>
	 * Output navigation menu.
	 */
	protected function parse_globalnavi($template = 'Sandbox/sidebar')
	{
		global $CONF, $manager, $blog;
		if ($blog) {
			$b =& $blog;
		} else {
			global $manager;
			$b =& $manager->getBlog($CONF['DefaultBlog']);
		}
		$bid   = $b->getID();
		$pages =  parent::getSpecialSkinParts($bid);
		if (count($pages) < 1) {
			return;
		}
		if (!is_array($pages)) {
			$pages = array($pages);
		}
		$template =& $manager->getTemplate($template);
		if (empty($template)) {
			$template = 'Sandbox/sidebar';
		}
		$outData  =  parent::getPageListData($pages, $template, $bid);
		echo TEMPLATE::fill($template['Sandbox_PagesList_Menu'], array('contents' => $outData));
	}

	// }}}
	// {{{ parse_text($extra, $item, $comment)

	/**
	 * Parse skinvar 'text'
	 *
	 * Skin variable parser.
	 * <%WPSandBax(text)%>
	 * Output defined sentens.
	 */
	protected function parse_text($extra, $item = false, $comment = false)
	{
		$cskinName = strtoupper(parent::$skin->name);
		if (!defined('__NSL_' . $cskinName)) {
			switch (parent::$skin->includeMode) {
				case 'skindir':
					global $DIR_SKINS;
					$language = ereg_replace('[\\|/]', '',getLanguageName());
					$filedir  = $DIR_SKINS . parent::$skin->includePrefix . 'language/';
					if (@file_exists($filedir . $language . '.php')) {
						require_once($filedir . $language . '.php');
					} elseif (@file_exists($filedir . 'english.php')) {
						require_once($filedir . 'english.php');
					} else {
						break;
					}
					break;
				case 'normal':
				default:
					break;
			}
		}
		if (defined($extra)) {
			eval("echo $extra;");
		} elseif (defined('__NSL_' . $cskinName . '_' . strtoupper($extra))) {
			$extra = '__NSL_' . $cskinName . '_' . strtoupper($extra);
			eval("echo $extra;");
		}
	}

	// }}}
	// {{{ parse_xmldeclaration()

	/**
	 * Parse skinvar 'stylesheeturl'
	 *
	 * Skin variable parser.
	 * <%WPSandBax(parse_xmldeclaration)%>
	 * Output XML declaration.
	 */
	protected function parse_xmldeclaration()
	{
		$ua = serverVar('HTTP_USER_AGENT');
		if (ereg("Windows", $ua) && ereg("MSIE", $ua)) {
			preg_match("|MSIE\s(\d{1,})\.|", $ua, $matches);
			if ($matches[1] <= 6) {
				return;
			}
		}
		echo '<' . '?xml version="1.0" encoding="' . _CHARSET .'"?' . '>' . "\n";
	}

	// }}}
	// {{{ parse_contenttype()

	/**
	 * Parse skinvar 'contenttype'
	 *
	 * Skin variable parser.
	 * <%WPSandBax(contenttype)%>
	 * Output HTML Content-Type fot <meta> tag.
	 */
	protected function parse_contenttype()
	{
		echo parent::$contentType;
	}

	// }}}
	// {{{ parse_stylesheeturl()

	/**
	 * Parse skinvar 'stylesheeturl'
	 *
	 * Skin variable parser.
	 * <%WPSandBax(stylesheeturl)%>
	 * Output URL of BLOG specified Cascading Style Sheets file.
	 */
	protected function parse_stylesheeturl()
	{
		global $CONF, $blog;
		if ($blog) {
			$b = &$blog;
		} else {
			global $manager;
			$b = &$manager->getBlog($CONF['DefaultBlog']);
		}
		$sandbox = parent::pluginCheck('WPSandBox');
		$cssName = $sandbox->getBlogOption($b->getID(), 'sandboxSkin');
		echo $CONF['SkinsURL'] . 'sandbox/skins/' . $cssName . '/style.css';
	}

	// }}}
	// {{{ parse_sandboxpostclass($extra, $item)

	/**
	 * Parse skinvar 'currentblog'
	 *
	 * Template variable parser.
	 * <%WPSandBax(currentblog, EXTRA)%>
	 * Output currentblog settings.
	 *
	 * @param string skinvar 2nd argument
	 */
	protected function parse_currentblog($extra)
	{
		global $blogid, $CONF, $manager;
		if (!$blogid) {
			$b = &$manager->getBlog($CONF['DefaultBlog']);
		} else {
			$b = &$manager->getBlog($blogid);
		}
		switch (strtolower($extra)) {
			case 'id':
				echo $b->getID();
				break;
			case 'name':
				echo htmlspecialchars($b->getName(), ENT_QUOTES);
				break;
			case 'shortname':
				echo htmlspecialchars($b->getShortName(), ENT_QUOTES);
				break;
			case 'description':
				echo htmlspecialchars($b->getDescription(), ENT_QUOTES);
				break;
			case 'url':
				echo htmlspecialchars($b->getURL(), ENT_QUOTES);
				break;
		}
	}

	// }}}
	// {{{ parse_date()

	/**
	 * parse template/templatecomment var 'date'
	 *
	 * Template variable parser.
	 * <%WPSandBax(date, format)%>
	 * Output formatted date via 'date' function.
	 * You can use ',' in format.
	 *
	 * @param string date/time format for 'date()' function
	 * @param object current item
	 */
	protected function parse_date($extra, $item = '', $comment = '')
	{
		if ($comment) {
			$timestamp = $comment['timestamp'];
		} elseif ($item) {
			$timestamp = $item->timestamp;
		} else {
			$timestamp = time();
		}
		echo date($extra, $timestamp);
	}

	// }}}

// }}}
// {{{ Private methods

	// {{{ indexPageBodyClass($catid, $tags, $scat)

	/**
	 * Class for <BODY> TAG in 'index' page.
	 *
	 * @param int category ID
	 * @param array selected tags
	 * @param int subcategory ID
	 */
	private function indexPageBodyClass($catid, $tags, $scat)
	{
		$ret = ' blog';
		if (!$catid && !$tags && !$scat && !(parent::$page)) {
			$ret .= ' home';
		}
		return $ret;
	}

	// }}}
	// {{{ archivePageBodyClass()

	/**
	 * Class for <BODY> TAG in 'archive' or 'archovelist' pages.
	 */
	private function archivePageBodyClass()
	{
		$ret = ' archive';
		if (parent::$skinType == 'archive') {
			$ret .= ' date';
			if (parent::$page > 0) {
				$ret .= ' date-paged-' . parent::$page;
			}
		}
		return $ret;
	}

	// }}}
	// {{{ archivePageBodyClass()

	/**
	 * Class for <BODY> TAG in 'member' page.
	 *
	 * @param object specific member object when the page is display
	 */
	private function memberPageBodyClass($member)
	{
		$ret = ' author author-' . $member->getDisplayName();
		if (parent::$page > 0) {
			$ret .= ' author-paged-' . parent::$page;
		}
		return $ret;
	}

	// }}}
	// {{{ itemClass($item, $b, $mode, $plugmulti)

	/**
	 * Class for <BODY> TAG in 'item' page.
	 * And class for each post block <DIV> tags.
	 *
	 * @param array each item data
	 * @param object specific blog object
	 * @param string 'body' or 'post'
	 * @param bool|object NP_MultipleCategories is installed or not
	 * @param bool|array NP_TagEX is installed or not
	 */
	private function itemClass($item, $b, $mode = 'body', $plugmulti = false, $tags = fales)
	{
		$published = getdate($item['timestamp']);
		$author    = MEMBER::createFromID($item['authorid']);
		$author    = $author->getDisplayName();
		$itemid    = intval($item['itemid']);
		extract($published);
		if ($mode == 'body') {
			$format = ' single s-y%04d s-m%02d s-d%02d s-h%02d postid-%d s-author-%s';
			$ret    = sprintf($format, $year, $mon, $mday, $hours, $itemid, $author);
			$jointC = ' s-category-';
		} elseif ($mode == 'post') {
			$format = 'hentry post page protected y%04d m%02d d%02d h%02d author-%s';
			$ret    = sprintf($format, $year, $mon, $mday, $hours, $itemid, $author);
			if ($item['idraft'] || $item['draft']) {
				$ret .= ' draft';
			} elseif ($item['timestamp'] < time() + ($b->getTimeOffset() * 3600)) {
				$ret .= ' publish';
			}
			$jointC = ' category-';
		}
		if ($plugmulti) {
			$multicats = array_map('trim', explode(',', $plugmulti->_getMultiCategories($item['itemid'])));
			$multicats = (is_array($multicats)) ? $multicats : array($multicats);
			$subcats   = array_map('trim', explode(',', $plugmulti->_getSubCategories($item['itemid'])));
			$subcats   = (is_array($subcats))   ? $subcats   : array($subcats);
			$category  = array_merge($subcats, $multicats);
			$ret      .= $jointC . implode($jointC, $category);
		} else {
			$ret      .= $jointC . $b->getCategoryName($item['catid']);
		}
		if (!empty($tags)) {
			if ($mode == 'body') {
				$ret .= ' s-tag-' . implode(' s-tag-', $tags);
			} elseif ($mode == 'post') {
				$ret .= ' tag' . self::formatItemTags($itemid, $tags);
			}
		}
		return $ret;
	}

	// }}}
	// {{{ formatItemTags($itemid, $words)

	/**
	 * Formatted tags string
	 *
	 * @param int selected itemID
	 * @param array selected tags
	 */
	private function formatItemTags($itemid, $words)
	{
		$query = 'SELECT itags as result FROM %s WHERE inum = %d';
		$tags  = quickQuery(sprintf($query, _TAGEX_TABLE, $itemid));
		$tags  = preg_split("/[\n,]+/", trim($tags));
		$count = false;
		$ret   = '';
		foreach ($tags as $tag) {
			if ($in_array($tag, $words)) {
				$ret .= ' tag-' . htmlspecialchars($tag, ENT_QUOTES, _CHARSET);
				$count++;
			}
		}
		if (!$count) {
			$ret .= ' untagged';
		}
		return $ret;
	}

	// }}}
	// {{{ tagcheck()

	/**
	 * Check selected tags
	 *
	 * @return bool|array if existstags
	 */
	private function tagCheck()
	{
		$tags = false;
		if ($plugtag = parent::pluginCheck('TagEX')) {
			$tags = $plugtag->getNoDecodeQuery('tag');
			if ($tags) {
				$tags = $plugtag->splitRequestTags($tags);
				$tags = (!empty($tags['or'])) ? array_merge($tags['and'], $tags['or']) : $tags['and'];
				$tags = array_map(array(&$plugtag, '_rawdecode'), $tags);
			}
		}
		return $tags;
	}

	// }}}

// }}}

}

